from __future__ import print_function
import sys

sys.path.append('..')
from ..Game import Game
from .HexLogic import Board
import numpy as np


class HexGame(Game):
    square_content = {-1: "B", +0: "0", +1: "R"}

    @staticmethod
    def getSquarePiece(piece):
        return HexGame.square_content[piece]

    def __init__(self, n):
        self.n = n

    def getInitBoard(self):
        # return initial board (numpy board)
        b = Board(self.n)
        return np.array(b.pieces)

    def getBoardSize(self):
        # (a,b) tuple
        return (self.n, self.n)

    def getActionSize(self):
        # return number of actions
        return self.n * self.n + 1

    def getNextState(self, board, player, action):
        # if player takes action on board, return next (board,player)
        # action must be a valid move
        if action == self.n * self.n:
            return (board, -player)
        b = Board(self.n)
        b.pieces = np.copy(board)
        move = (int(action / self.n), action % self.n)
        b.execute_move(move, player)
        return (b.pieces, -player)

    def getValidMoves(self, board, player):
        # return a fixed size binary vector
        valids = [0] * self.getActionSize()
        b = Board(self.n)
        b.pieces = np.copy(board)
        legalMoves = b.get_legal_moves(player)
        if len(legalMoves) == 0:
            valids[-1] = 1
            return np.array(valids)
        for x, y in legalMoves:
            valids[self.n * x + y] = 1
        return np.array(valids)

    def getGameEnded(self, board, player):
        # return 0 if not ended, 1 if player won, -1 if player lost
        b = Board(self.n)
        b.pieces = np.copy(board)
        return player * b.get_game_result()

    def getCanonicalForm(self, board, player):
        # return state if player==1, else return -state if player==-1
        return board if player == 1 else player * np.rot90(np.fliplr(board))

    def remapAction(self, action):
        action = action // self.n + action % self.n * self.n
        return action

    def getSymmetries(self, board, pi):
        # mirror, rotational
        assert (len(pi) == self.n**2 + 1)  # 1 for pass
        pi_board = np.reshape(pi[:-1], (self.n, self.n))
        l = []

        for i in range(2, 5, 2):
            newB = np.rot90(board, i)
            newPi = np.rot90(pi_board, i)
            l += [(newB, list(newPi.ravel()) + [pi[-1]])]
        return l

    def stringRepresentation(self, board):
        return board.tostring()

    def stringRepresentationReadable(self, board):
        board_s = "".join(self.square_content[square] for row in board
                          for square in row)
        return board_s

    def getScore(self, board, player):
        return player * board.get_game_result()

    @staticmethod
    def display(board):
        n = board.shape[0]
        print("    ", end="")
        alphabet = "ABCDEFGHIJK"
        for y in range(n):
            print(alphabet[y], end=" ")
        print("")
        print("-----------------------")
        for y in range(n):
            print(str(y + 1).zfill(2), "|", end="")  # print the row #
            for x in range(n):
                piece = board[y][x]  # get the piece to print
                print(HexGame.square_content[piece], end=" ")
            print("|")

        print("-----------------------")
